import { Box, Button, Grid, Typography } from '@mui/material';
import { useEffect, useState } from 'react';

import Disbursement from '../../api/disbursement/disbursement';
import FeeManager from '../../api/fee/fee-manager';
import TokenManager, { Network, Token } from '../../api/token/token-manager';
import Transaction from '../../api/transaction/transaction';
import CSVErrors from '../../components/csv-disbursements/csv-errors';
import DisbusementPopup from '../../components/csv-disbursements/disbursement-popup';
import HomeReviewCSV from '../../components/csv-disbursements/home-review-csv';
import HomeUploadCSV from '../../components/csv-disbursements/home-upload-csv';
import SaveDisbursementPopup from '../../components/csv-disbursements/save-disbursement-popup';
import MainLayout from '../../components/HOCs/main-layout';
import LoadingWithProgressPopup from '../../components/loading-with-progress-popup';
import {
    confirmDisbursementDialog,
    payDisbursementDialog,
    successDisbursementDialog
} from '../../components/shared/dialogs/disbursement-flow';
import { createDialog } from '../../components/shared/dialogs/dynamic-dialogs';
import { DialogTypes } from '../../components/shared/dialogs/dynamic-dialogs/types-mapping';
import { DisbursementFlow, DisbursementType } from '../../constants/disbursement-flow';
import { checkForErrors, CSVError } from '../../libs/csv-validation';

export default function CSVDisbursementPage() {
    const [title, setTitle] = useState('');
    const [token, setToken] = useState('');
    const [abi, setAbi] = useState(null);
    const [tokens, setTokens] = useState<Token[]>([]);
    const [network, setNetwork] = useState<Network>(null);
    const [transactions, setTransactions] = useState<Array<Transaction>>([]);

    const [flow, setFlow] = useState(DisbursementFlow.START);
    const [disbursement, setDisbursement] = useState<Disbursement>(null);

    const [csvErrors, setCSVErrors] = useState<Array<CSVError>>([]);
    const [csvAnalysisProgress, setCSVAnalysisProgress] = useState<number>(0);
    const [csvAnalysisTotal, setCSVAnalysisTotal] = useState<number>(0);
    const [minAmount, setMinAmount] = useState<number>(0);
    const [transactionFee, setTransactionFee] = useState<number>(0);

    useEffect(() => {
        if (token == 'SLP') {
            const getSlpFee = async () => {
                const slpFee = await FeeManager.getSLP();
                if (slpFee) {
                    const minAmount = !Number.isNaN(Number(slpFee.minimumAmount))
                        ? Number(slpFee.minimumAmount)
                        : 0;
                    const transactionFee = !Number.isNaN(Number(slpFee.gasFee.amount))
                        ? Number(slpFee.gasFee.amount)
                        : 0;
                    setMinAmount(minAmount);
                    setTransactionFee(transactionFee);
                }
            };
            getSlpFee().then();
        }
    }, []);

    useEffect(() => {
        const getTokens = async () => {
            const { tokens, abi } = await TokenManager.getTokens();
            setTokens(tokens);
            setAbi(abi);
        };
        getTokens().then();
    }, []);

    useEffect(() => {
        switch (flow) {
            case DisbursementFlow.CONFIRM:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_CONFIRM, () =>
                    confirmDisbursementDialog({
                        open: true,
                        data: {
                            transactions,
                            token,
                            transactionFee,
                            network,
                            abi,
                            disbursement
                        },
                        onSubmit: (flow) => {
                            flow && setFlow(flow);
                        }
                    })
                );
                break;
            case DisbursementFlow.PAY:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_PAY, () =>
                    payDisbursementDialog({
                        open: true,
                        data: { transactions, token, disbursement, transactionFee, abi, network },
                        onSubmit: () => setFlow(DisbursementFlow.SUCCESS)
                    })
                );
                break;
            case DisbursementFlow.SUCCESS:
                createDialog(DialogTypes.DISBURSEMENT_FLOW_SUCCESS, () =>
                    successDisbursementDialog({
                        open: true,
                        disbursement
                    })
                );
                break;
        }
    }, [flow]);

    const updateFlow = async (flow: DisbursementFlow, disbursement: Disbursement = null) => {
        if (disbursement != null) {
            setDisbursement(disbursement);
        }
        setFlow(flow);
    };

    const onUploadCSVClick = async () => {
        setFlow(DisbursementFlow.UPLOAD_CSV);
    };

    const onTransactionsUploaded = async (
        title: string,
        token: string,
        network: Network,
        transactions: Array<Transaction>
    ) => {
        setTitle(title);
        setToken(token);
        setNetwork(network);
        setFlow(DisbursementFlow.UPLOADING_CSV);

        const errors: CSVError[] = [];

        for (let i = 0; i < transactions.length; i++) {
            const error = await checkForErrors(transactions[i], minAmount, token);

            setCSVAnalysisProgress(i);
            setCSVAnalysisTotal(transactions.length);

            if (error != null) {
                errors.push(error);
            }
        }

        if (errors.length == 0) {
            setTransactions(transactions);
            setFlow(DisbursementFlow.REVIEW_CSV);
        } else {
            setCSVErrors(errors);
            setFlow(DisbursementFlow.CSV_ERROR);
        }
    };

    const onCloseDisbursementPopup = () => {
        setFlow(DisbursementFlow.START);
    };

    const hasTransactions = (): boolean => {
        return transactions && transactions.length > 0;
    };

    const onDisburseClick = async (event) => {
        event.preventDefault();

        setFlow(DisbursementFlow.SAVE_TRANSACTIONS);
    };

    return (
        <>
            <MainLayout>
                <Box sx={{ p: 6 }}>
                    <Typography variant="h1" className="bottom-30">
                        1-Click Disbursement
                    </Typography>

                    {title && <Typography variant="h2">{title}</Typography>}

                    {flow == DisbursementFlow.REVIEW_CSV && !hasTransactions() && (
                        <Typography className="top-30" variant="h5" style={{ color: 'red' }}>
                            Uploaded CSV is empty
                        </Typography>
                    )}

                    {(flow == DisbursementFlow.START ||
                        flow == DisbursementFlow.UPLOAD_CSV ||
                        flow == DisbursementFlow.CSV_ERROR ||
                        (flow == DisbursementFlow.REVIEW_CSV && !hasTransactions())) && (
                        <HomeUploadCSV
                            onUploadCSVClick={onUploadCSVClick}
                            flow={flow}
                            error={flow == DisbursementFlow.CSV_ERROR}
                        />
                    )}

                    {(flow == DisbursementFlow.REVIEW_CSV ||
                        flow == DisbursementFlow.SAVE_TRANSACTIONS ||
                        flow == DisbursementFlow.CONFIRM ||
                        flow == DisbursementFlow.PAY ||
                        flow == DisbursementFlow.SUCCESS) &&
                        hasTransactions() && (
                            <div className="top-10">
                                <HomeReviewCSV transactions={transactions} token={token} />

                                <Grid
                                    className="top-30 bottom-30"
                                    container
                                    justifyContent="center"
                                >
                                    <Button
                                        variant="contained"
                                        component="label"
                                        onClick={onDisburseClick}
                                    >
                                        SEND DISBURSEMENT
                                    </Button>
                                </Grid>
                            </div>
                        )}

                    <LoadingWithProgressPopup
                        show={flow == DisbursementFlow.UPLOADING_CSV}
                        message={'Uploading and analyzing CSV...'}
                        progress={csvAnalysisProgress}
                        total={csvAnalysisTotal}
                    />

                    {flow == DisbursementFlow.UPLOAD_CSV && (
                        <DisbusementPopup
                            onTransactionsUploaded={onTransactionsUploaded}
                            onCloseDisbursementPopup={onCloseDisbursementPopup}
                            show={true}
                            tokens={tokens}
                        />
                    )}

                    {flow == DisbursementFlow.CSV_ERROR && <CSVErrors errors={csvErrors} />}

                    {flow == DisbursementFlow.SAVE_TRANSACTIONS && (
                        <SaveDisbursementPopup
                            title={title}
                            token={token}
                            network={network}
                            updateFlow={updateFlow}
                            transactions={transactions}
                            type={DisbursementType.CSV}
                        />
                    )}
                </Box>
            </MainLayout>
        </>
    );
}
